void bullets :: init()
{
    using namespace bullets;
    float trace_width   = GetFloat("trace_width");
    float trace_length  = GetFloat("trace_length");
    bullet_speed        = GetFloat("bullet_speed");
    fire_delay          = GetFloat("fire_delay");
    offset_x            = GetFloat("offset_x");
    offset_y            = GetFloat("offset_y");
    kickback            = GetFloat("kickback");
    cooldown_step       = GetFloat("cooldown_step");
    recoil_cap          = GetFloat("recoil_cap");
    trigger_pulled      = false;
    time_stack          = 0.0f;
    recoil_yaw          = 0.0f;
    recoil_pitch        = 0.0f;
    nextbullet          = 0u;
    n_bullet    .resize(BULLET_MAX);
    bb_dot      .resize(BULLET_MAX);
    bb_trace    .resize(BULLET_MAX);
//#ifdef USE_BULLET
//  callbacks   .resize(BULLET_MAX);
//#endif
    FOR(BULLET_MAX)
    {
        // trace
        bb_trace[i] = (BillboardChain *) bbchfact.createInstance ("bullet"+TO_STR(i), scmgr);

        bb_trace[i]->setQueryFlags(qf_effect);

        bb_trace[i] -> setMaterialName("jokoon/bullet_trace");
        bb_trace[i] -> setTextureCoordDirection(BillboardChain :: TCD_V);
        bb_trace[i] -> setUseTextureCoords(true);
        bb_trace[i] -> setMaxChainElements(2);
#if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 8
        bb_trace[i] -> addChainElement (0, BillboardChain::Element
                                        (Vec3(0, 0, 0), trace_width, 0, ColourValue(), Ogre::Quaternion::IDENTITY));
        bb_trace[i] -> addChainElement (0, BillboardChain::Element
            (Vec3(0, 0, trace_length), trace_width, 0, ColourValue(), Ogre::Quaternion::IDENTITY));
#elif OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 7
        bb_trace[i] -> addChainElement (0, BillboardChain::Element
                                        (Vec3(0, 0, 0), trace_width, 0, ColourValue()));
        bb_trace[i] -> addChainElement (0, BillboardChain::Element
                                        (Vec3(0, 0, trace_length), trace_width, 0, ColourValue()));
#endif
        // dot
        bb_dot[i] = scmgr -> createBillboardSet();
        bb_dot[i] -> createBillboard(Vec3(0,0,0));
        bb_dot[i] -> setMaterialName("jokoon/bullet_dot");
        float scale = GetFloat("bullet_dot");
        bb_dot[i]
            -> getMaterial() -> getTechnique(0u) -> getPass(0u)
            -> getTextureUnitState(0u) -> setTextureScale(scale, scale);
        // nodes
        n_bullet[i] = n_root -> createChildSceneNode("bullet"+TO_STR(i));
        n_bullet[i] -> attachObject(bb_trace[i]);
        n_bullet[i] -> attachObject(bb_dot[i]);
    }
}
#define N_BUFFERS 32
void bullets :: fire_trace()
{
    n_bullet[nextbullet] -> setPosition
        (camera -> getDerivedPosition() + Vec3(0, offset_x, offset_y));
    n_bullet[nextbullet] -> setOrientation(camera -> getDerivedOrientation());
    ++nextbullet; nextbullet %= BULLET_MAX;
    if(recoil_pitch < recoil_cap)
        recoil_pitch += kickback;
    if(recoil_pitch > recoil_cap)
        recoil_pitch -= recoil_pitch - recoil_cap;
    time_stack = 0.0f;
}
void bullets :: update_bullets()
{
    FOR(BULLET_MAX)
        n_bullet[i] -> translate
            (0, 0, -timeSinceLastFrame * bullet_speed, Node::TS_LOCAL);
    
    time_stack += timeSinceLastFrame;
    if (time_stack > fire_delay && trigger_pulled)
        fire_trace();

    if(recoil_pitch > 0.0f)
        recoil_pitch -= cooldown_step;
}
void bullets :: trigger_pull() { fire_trace(); trigger_pulled = true; }
void bullets :: trigger_release() { trigger_pulled = false; }
/*
//// rest of update bullet

    // bullet raycast
    // todo
    ray_start = camera ->getDerivedPosition();
    ray_end = ray_start + camera ->getDerivedDirection();

    arg_start = btVector3(ray_start.x, ray_start.y, ray_start.z);
    arg_end = btVector3(ray_end.x, ray_end.y, ray_end.z);
    // btCollisionWorld :: ClosestRayResultCallback RayCallback(arg_start, arg_end);
    // Perform raycast
 
    if(callbacks[nextbullet].hasHit())
    {
        //End = RayCallback.m_hitPointWorld;
        //Normal = RayCallback.m_hitNormalWorld;
        // Do some clever stuff here
    }
    collisionWorld->rayTest(arg_start, arg_end, callbacks[nextbullet]);
    

    //if(was_fired == true)
    //{


*/